package solver

import (
	"log"
)

func clearupHouse(house House, solvedNum int) {
	cand := house.cells[solvedNum].value - 1
	for i, cell := range house.cells {
		if i == solvedNum || cell.solved() {
			continue
		}
		cell.removeCand(cand)
	}
}

func (g *Grid) Clearup() {
	for rowNum := 0; rowNum < 9; rowNum++ {
		for colNum := 0; colNum < 9; colNum++ {
			if !g.cells[rowNum][colNum].solved() {
				continue
			}
			clearupHouse(g.rows[rowNum], colNum)
			clearupHouse(g.cols[colNum], rowNum)
			boxNum, cellNum := calcBoxAndCellNum(rowNum, colNum)
			clearupHouse(g.boxes[boxNum], cellNum)
		}
	}
}

func (g *Grid) LastOneHouse(house House) (used bool) {
	if house.solvedCount != 8 {
		return
	}

	var cell *Cell
	for _, cell = range house.cells {
		if cell.solved() {
			continue
		}
		for cand, boolCand := range cell.cands {
			if !boolCand {
				continue
			}
			value := cand + 1
			g.solveOneCell(cell.rowNum, cell.colNum, value)
			log.Printf("r%vc%v %v %v Last One", cell.rowNum, cell.colNum, value, house.HouseTypeName())
			used = true
			return
		}
	}
	return
}

func (g *Grid) solveOneCell(rowNum int, colNum int, value int) {
	g.cells[rowNum][colNum].setValue(value)
	g.rows[rowNum].solvedCount += 1
	g.cols[colNum].solvedCount += 1
	boxNum, cellNum := calcBoxAndCellNum(rowNum, colNum)
	g.boxes[boxNum].solvedCount += 1
	g.solvedCount += 1
	clearupHouse(g.rows[rowNum], colNum)
	clearupHouse(g.cols[colNum], rowNum)
	clearupHouse(g.boxes[boxNum], cellNum)
}

/*
	func (g *Grid) LastOne() (used bool) {
		return g.doStrategy(g.LastOneHouse)
	}
*/
func (g *Grid) LastOneBox() (used bool) {
	for _, box := range g.boxes {
		if g.LastOneHouse(box) {
			return true
		}
	}
	return false
}

func (g *Grid) LastOneRow() (used bool) {
	for _, row := range g.rows {
		if g.LastOneHouse(row) {
			return true
		}
	}
	return false
}

func (g *Grid) LastOneCol() (used bool) {
	for _, col := range g.cols {
		if g.LastOneHouse(col) {
			return true
		}
	}
	return false
}

func (g *Grid) HiddenSingleHouse(house House) (used bool) {
	candCells, candCounts := sumupCandCells(house)
	for cand, counts := range candCounts {
		if counts != 1 {
			continue
		}
		for cellNum, candCell := range candCells[cand] {
			if !candCell {
				continue
			}
			solved := house.cells[cellNum]
			g.solveOneCell(solved.rowNum, solved.colNum, cand+1)
			log.Printf("r%vc%v %v %v Hidden Single", solved.rowNum, solved.colNum, cand+1,
				house.HouseTypeName())
			return true
		}
	}
	return
}

func (g *Grid) HiddenSingleRow() (used bool) {
	for _, row := range g.rows {
		if g.HiddenSingleHouse(row) {
			return true
		}
	}
	return false
}

func (g *Grid) HiddenSingleCol() (used bool) {
	for _, col := range g.cols {
		if g.HiddenSingleHouse(col) {
			return true
		}
	}
	return false
}

func (g *Grid) HiddenSingleBox() (used bool) {
	for _, box := range g.boxes {
		if g.HiddenSingleHouse(box) {
			return true
		}
	}
	return false
}

func (g *Grid) NakedSingle() (used bool) {
	for rowNum, row := range g.rows {
		for colNum, cell := range row.cells {
			if cell.solved() || cell.candCount != 1 {
				continue
			}
			value := intsFromBools(cell.cands)[0] + 1
			g.solveOneCell(rowNum, colNum, value)
			log.Printf("r%vc%v %v %v", rowNum, colNum, value, "Naked Single")
			return true
		}
	}
	return false
}
